#include "stdbool.h"
#include "stdio.h"
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#include <string.h>
#include <stdlib.h>
#include "canvas_tool.h"


#define DISPLAY_TYPE_BLACK_WHITE 0X01
#define DISPLAY_TYPE_3_GRAY_COLOR 0X02
#define DISPLAY_TYPE_4_GRAY_COLOR 0X03
#define DISPLAY_TYPE_8_GRAY_COLOR 0X04
#define DISPLAY_TYPE_16_GRAY_COLOR 0X05
#define DISPLAY_TYPE_RED_BLACK_WHITE 0X06
#define DISPLAY_TYPE_YELLOW_BLACK_WHITE 0X07
#define DISPLAY_TYPE_RED_YELLOW_BLACK_WHITE 0X08
#define DISPLAY_TYPE_6_COLOR 0X09
#define DISPLAY_TYPE_7_COLOR 0X09
#define DISPLAY_TYPE_16_COLOR 0X0A
#define DISPLAY_TYPE_FULL_RGB 0X0B

#define LOG_TAG "canvas_tool"

#define canvas_tool_version "1.3"

#ifdef __cplusplus
extern "C" {
#endif


void print_hex(const uint8_t *data, size_t size);
static int covor_image_5inch79_3color(const uint32_t *image, int width, int height, const char *path);
static int covor_image_7inch5_4color(const uint32_t *image, int width, int height, const char *path);
static int covor_image_13inch3_6color(const uint32_t *image, int width, int height, const char *path);

int cover_to_epaper(const uint32_t *image, int width, int height, int display_type, const char *path)
{
    printf("\n=== cover_to_epaper called ===\n");
    if (image == NULL)
    {
        printf("image addr is NULL");
        return -EINVAL;
    }

    printf("version %s width %d height %d display_type %d path %s", canvas_tool_version, width, height, display_type, path);
    if (display_type == DISPLAY_TYPE_RED_YELLOW_BLACK_WHITE) {
        printf("DISPLAY_TYPE_RED_YELLOW_BLACK_WHITE");
        return covor_image_7inch5_4color(image, width, height, path);
    }
        
    if (display_type == DISPLAY_TYPE_RED_BLACK_WHITE){
        printf("DISPLAY_TYPE_RED_BLACK_WHITE");
        return covor_image_5inch79_3color(image, width, height, path);
    }
        
    if (display_type == DISPLAY_TYPE_FULL_RGB){
        printf("DISPLAY_TYPE_RED_BLACK_WHITE");
            return covor_image_13inch3_6color(image, width, height, path);
    }
    
    return -ENXIO;
}

static int covor_image_5inch79_3color(const uint32_t *image, int width, int height, const char *path)
{
    int ret = 0;
    uint8_t pix = 0;
    uint32_t dot = 0;
    uint32_t k = 0;

    uint8_t *epaper_buffer0 = NULL;

    epaper_buffer0 = (uint8_t *)malloc(sizeof(uint8_t) * width * height / 4);
    if (epaper_buffer0 == NULL)
    {
        printf("%s %d malloc faild!", __func__, __LINE__);
        ret = -ENOMEM;
        goto exit;
    }

    memset(epaper_buffer0, 0x00, width * height / 4 * sizeof(uint8_t));

    for (uint32_t i = 0; i < width * height; i++)
    {
        if ((image[i] & 0x00ffffff) == WHITE)
        {
            pix = 0x00;
            epaper_buffer0[i / 8] |= pix << (7 - (i % 8));
        }
        else if ((image[i] & 0x00ffffff) == BLACK)
        {
            pix = 0x1;
            epaper_buffer0[i / 8] |= pix << (7 - (i % 8));
        }
        else if ((image[i] & 0x00ffffff) == RED)
        {
            pix = 0x01;
            epaper_buffer0[(width * height) / 8 + i / 8] |= pix << (7 - (i % 8));
        }
    }

    FILE *fp = fopen(path, "w");
    if (fp != NULL)
    {
        fwrite(epaper_buffer0, sizeof(uint8_t) * height * width / 4, 1, fp);
        fflush(fp);
        fclose(fp);
    }
    else
    {
        printf("%s %d fopen %s faild!", __func__, __LINE__, path);
        ret = -ENOENT;
    }

exit:
    if (epaper_buffer0 != NULL)
    {
        free(epaper_buffer0);
    }
    return ret;
}

static int covor_image_7inch5_4color(const uint32_t *image, int width, int height, const char *path)
{
    int ret = 0;
    uint8_t pix = 0;
    uint32_t dot = 0;
    uint32_t k = 0;

    uint8_t *epaper_buffer0 = NULL;

    epaper_buffer0 = (uint8_t *)malloc(sizeof(uint8_t) * width * height / 4);
    if (epaper_buffer0 == NULL)
    {
        printf("%s %d malloc faild!", __func__, __LINE__);
        ret = -ENOMEM;
        goto exit;
    }

    memset(epaper_buffer0, 0x00, width * height / 4 * sizeof(uint8_t));

    for (uint32_t i = 0; i < width * height; i++)
    {
        if ((image[i] & 0x00ffffff) == WHITE)
        {
            pix = WHITE_EPAPER;
        }
        else if ((image[i] & 0x00ffffff) == BLACK)
        {
            pix = BLACK_EPAPER;
        }
        else if ((image[i] & 0x00ffffff) == RED)
        {
            pix = RED_EPAPER;
        }
        else if ((image[i] & 0x00ffffff) == YELLOW)
        {
            pix = YELLOW_EPAPER;
        }
        else
        {
            pix = BLACK_EPAPER;
        }
        epaper_buffer0[i / 4] |= pix << (6 - (i % 4) * 2);
    }

    FILE *fp = fopen(path, "w");
    if (fp != NULL)
    {
        fwrite(epaper_buffer0, sizeof(uint8_t) * height * width / 4, 1, fp);
        fflush(fp);
        fclose(fp);
    }
    else
    {
        printf("%s %d fopen %s faild!", __func__, __LINE__, path);
        ret = -ENOENT;
    }

exit:

    if (epaper_buffer0 != NULL)
    {
        free(epaper_buffer0);
    }
    return ret;
}

static int covor_image_13inch3_6color(const uint32_t *image, int width, int height, const char *path)
{
    int ret = 0;
    uint8_t pix = 0;
    uint32_t dot = 0;
    uint32_t k = 0;

    uint8_t *epaper_buffer0 = NULL;
    uint32_t buffer_size = sizeof(uint8_t) * width * height / 2;

    // print_hex((const uint8_t *)&image[480000], 4096);

    epaper_buffer0 = (uint8_t *)malloc(buffer_size);
    if (epaper_buffer0 == NULL)
    {
        printf("%s %d malloc faild!", __func__, __LINE__);
        ret = -ENOMEM;
        goto exit;
    }

    memset(epaper_buffer0, 0x00, buffer_size);

    for (uint32_t i = 0; i < height; i++)
    {
        for (uint32_t j = 0; j < width / 2; j++)
        {
            pix = 0;
            dot = j + width * i;
            if ((image[dot] & 0x00ffffff) == WHITE)
            {
                pix = WHITE_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == BLACK)
            {
                pix = BLACK_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == RED)
            {
                pix = RED_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == GREEN)
            {
                pix = GREEN_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == BLUE)
            {
                pix = BLUE_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == YELLOW)
            {
                pix = YELLOW_EPAPER;
            }

            if ((dot % 2) == 1)
            {
                epaper_buffer0[k / 2] |= pix;
            }
            else
            {
                epaper_buffer0[k / 2] |= pix << 4;
            }
            k++;
        }
    }

    for (uint32_t i = 0; i < height; i++)
    {
        for (uint32_t j = width / 2; j < width; j++)
        {
            pix = 0;
            dot = j + width * i;
            if ((image[dot] & 0x00ffffff) == WHITE)
            {
                pix = WHITE_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == BLACK)
            {
                pix = BLACK_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == RED)
            {
                pix = RED_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == GREEN)
            {
                pix = GREEN_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == BLUE)
            {
                pix = BLUE_EPAPER;
            }
            else if ((image[dot] & 0x00ffffff) == YELLOW)
            {
                pix = YELLOW_EPAPER;
            }

            if ((dot % 2) == 1)
            {
                epaper_buffer0[k / 2] |= pix;
            }
            else
            {
                epaper_buffer0[k / 2] |= pix << 4;
            }
            k++;
        }
    }

    FILE *fp = fopen(path, "w");
    if (fp != NULL)
    {
        fwrite(epaper_buffer0, buffer_size, 1, fp);
        fflush(fp);
        fclose(fp);
    }
    else
    {
        printf("%s %d fopen %s faild!", __func__, __LINE__, path);
        ret = -ENOENT;
    }

exit:

    if (epaper_buffer0 != NULL)
    {
        free(epaper_buffer0);
    }
    return ret;
}

// 以十六进制格式打印数据
__attribute__((visibility("default")))
void print_hex(const uint8_t *data, size_t size)
{
    char buffer[128]; // 用于存储一行十六进制数据
    int line_offset = 0;

    for (size_t i = 0; i < size; ++i)
    {
        // 每16个字节一行
        if (i % 16 == 0 && i != 0)
        {
            buffer[line_offset] = '\0';
            printf("%s", buffer); // 打印一行十六进制数据
            line_offset = 0;
        }

        // 格式化每个字节的十六进制值
        line_offset += snprintf(buffer + line_offset, sizeof(buffer) - line_offset, "%02X ", data[i]);

        // 确保不会超出缓冲区大小
        if (line_offset >= sizeof(buffer) - 1)
        {
            buffer[line_offset] = '\0';
            printf("%s", buffer);
            line_offset = 0;
        }
    }

    // 打印最后剩余的部分
    if (line_offset > 0)
    {
        buffer[line_offset] = '\0';
        printf("%s", buffer);
    }
}

#ifdef __cplusplus
}
#endif
